#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFileInfo>
#include <Qsci/qsciscintillabase.h>
#include <Qsci/qscidocument.h>
#include <QToolButton>
#include <QDir>
#include <QFileDialog>
#include "lualexer.h"
#include <QMessageBox>
#include <QWebFrame>
#include <QScrollBar>
#include <QComboBox>
#include <QProcess>
#include "resources.h"
#include <QPixmap>


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)/*,
    ui(new Ui::MainWindow)*/
{

    SettingsManager::Instance();
    m_projectScrollPosition = 0;
    m_settingsScrollPosition = 0;
    m_navigationManager = new NavigationManager;
    m_processFunctionsListChanges = true;

    m_projectManager = new ProjectManager(SettingsManager::Instance()->getLastProject());
    m_processTabChanges = true;

    m_gotoControl = new GoToControl(this);
    m_gotoControl->setProjectManager(m_projectManager);
    connect(m_gotoControl, SIGNAL(itemChosen(QString)), this, SLOT(onGoToChosen(QString)));

    QVBoxLayout * layout = new QVBoxLayout;

    setupToolbar(layout);
    //setup search panel
    m_searchPanel = new SearchPanel;
    layout->addWidget(m_searchPanel);
    m_searchPanel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
    connect(m_searchPanel, SIGNAL(onHide()), this, SLOT(onSearchPanelHide()));

    m_grepPanel = new GrepPanel;
    layout->addWidget(m_grepPanel);    
    connect(m_grepPanel, SIGNAL(donePressed()), this, SLOT(onGrepDonePressed()));
    connect(m_grepPanel, SIGNAL(grepStarted(QString)), this, SLOT(onGrepPressed(QString)));

    m_grepManager = new GrepManager;

    setupTabbar(layout);

    m_projectFilter = new QLineEdit;
    layout->addWidget(m_projectFilter);
    connect(m_projectFilter, SIGNAL(textChanged(QString)), this, SLOT(onProjectFilterChanged(QString)));

    m_functionsList = new QComboBox;
    layout->addWidget(m_functionsList);
    connect(m_functionsList, SIGNAL(currentIndexChanged(QString)), this, SLOT(onFunctionChosen(QString)));




    m_projectView = new QWebView;
    m_projectView->setSizePolicy(QSizePolicy::Expanding,
                            QSizePolicy::Expanding);

    layout->addWidget(m_projectView);


    m_dumpView = new QTextBrowser;
    m_dumpView->setSizePolicy(QSizePolicy::Expanding,
                            QSizePolicy::Expanding);

    layout->addWidget(m_dumpView);
    m_dumpView->setOpenLinks(false);
    m_dumpView->setOpenExternalLinks(false);

    setupCodeEditor(layout);    
    m_searchPanel->setEditor(m_codeEditor);

    QWidget *window = new QWidget();
    window->setLayout(layout);

    setCentralWidget(window);

    if(SettingsManager::Instance()->getLastProject().length() == 0)
        openProjectTab();
    else
    {
        //reopen tabs
        reopenTabs();
    }

    connect(m_projectView, SIGNAL(linkClicked(const QUrl)), this, SLOT(onLinkClicked(const QUrl)));
    m_projectView->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);

    connect(m_dumpView, SIGNAL(anchorClicked(const QUrl)), this, SLOT(onLinkClicked(const QUrl)));

    showGrepPanel(false);

    connect(m_projectView->page(), SIGNAL(scrollRequested(int,int,QRect)), this, SLOT(onWebViewScrolled(int,int,QRect)));
    setupStyleSheet();
}

//**************** codeEditor setup********************
void MainWindow::setupCodeEditor(QVBoxLayout * aLayout)
{
    m_codeEditor = new CodeEditor;
    m_codeEditor->setSizePolicy(QSizePolicy::Expanding,
                            QSizePolicy::Expanding);
    aLayout->addWidget(m_codeEditor);

    LuaLexer * lexer = new LuaLexer(this);
    m_codeEditor->setLexer(lexer);
    m_codeEditor->setProjectManager(m_projectManager);

    m_codeEditor->hide();
    m_functionsList->hide();
    QFont font = QFont ("DejaVu Sans");
    font.setPointSize (12);
    m_codeEditor->setFont(font);
    m_codeEditor->setCaretLineVisible(true);
    //line color
    m_codeEditor->setCaretLineBackgroundColor(QColor("gainsboro"));

    //auto indent
    m_codeEditor->setAutoIndent(true);
    m_codeEditor->setIndentationGuides(true);
    m_codeEditor->setIndentationsUseTabs(true);
    m_codeEditor->setTabIndents(true);
    //m_codeEditor->setBackspaceUnindents(true);

    //End of line symbol
    #if defined Q_WS_X11
    m_codeEditor->setEolMode(QsciScintilla::EolUnix);
    #elif defined Q_WS_WIN
    m_codeEditor->setEolMode(QsciScintilla::EolWindows);
    #elif defined Q_WS_MAC
    m_codeEditor->setEolMode(QsciScintilla::EolMac);
    #endif

    //margin color
    m_codeEditor->setMarginsBackgroundColor(QColor("gainsboro"));
    //show line numbers
    m_codeEditor->setMarginLineNumbers(1, true);
    //width to fit 1000
    m_codeEditor->setMarginWidth(1, QString("1000"));

    //braces matching
    m_codeEditor->setBraceMatching(QsciScintilla::SloppyBraceMatch);
    //braces matching color
    m_codeEditor->setMatchedBraceBackgroundColor(Qt::yellow);
    m_codeEditor->setUnmatchedBraceForegroundColor(Qt::blue);


    connect(m_codeEditor, SIGNAL(textChanged()), this, SLOT(onTextChanged()));

    /*connect(textEdit, SIGNAL(cursorPositionChanged(int, int)),
     this, SLOT(cursorMoved(int, int)));*/
    connect(m_codeEditor, SIGNAL(userListActivated(int,QString)), this, SLOT(onCompletionSelected(int,QString)));
    m_codeEditor->setTabWidth(4);
    m_codeEditor->setMouseTracking(true);
    connect(m_codeEditor, SIGNAL(linkClicked(QString)), this, SLOT(onEditorLinkClicked(QString)));
    connect(m_codeEditor, SIGNAL(scrolled(int)), this, SLOT(onCodeEditorScrolled(int)));
    connect(m_codeEditor, SIGNAL(searchRequested()), this, SLOT(onSearchRequested()));
    connect(m_codeEditor, SIGNAL(hideSearch()), m_searchPanel, SLOT(hide()));

    m_codeEditor->initFromSettings();
}


void setIcon(QIcon & aIcon, const unsigned char *aData, int aDataLength)
{
    QPixmap temp;
    temp.loadFromData(aData, aDataLength);
    aIcon.addPixmap(temp);
}


void MainWindow::setupToolbar(QVBoxLayout *aLayout)
{
    m_toolbar = addToolBar("main toolbar");
    aLayout->addWidget(m_toolbar);
    m_toolbar->setIconSize(QSize(32, 32));
    m_toolbar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
    setIcon(m_saveImage, Resources::save_png, sizeof(Resources::save_png));
    setIcon(m_saveAllImage, Resources::save_all_png, sizeof(Resources::save_all_png));
    setIcon(m_quitImage, Resources::quit_png, sizeof(Resources::quit_png));
    setIcon(m_openProjectImage, Resources::open_png, sizeof(Resources::open_png));
    setIcon(m_addFilesImage, Resources::add_file_png, sizeof(Resources::add_file_png));
    setIcon(m_importDirectoryImage, Resources::import_png, sizeof(Resources::import_png));
    setIcon(m_newProjectImage, Resources::new_project_png, sizeof(Resources::new_project_png));
    setIcon(m_findImage, Resources::find_png, sizeof(Resources::find_png));
    setIcon(m_forwardImage, Resources::forward_png, sizeof(Resources::forward_png));
    setIcon(m_backImage, Resources::back_png, sizeof(Resources::back_png));
    setIcon(m_checkImage, Resources::check_png, sizeof(Resources::check_png));
    setIcon(m_grepImage, Resources::grep_png, sizeof(Resources::grep_png));
    setIcon(m_settingsImage, Resources::settings_png, sizeof(Resources::settings_png));
    connect(m_toolbar, SIGNAL(actionTriggered (QAction *)), this, SLOT(onToolbarAction(QAction*)));
}

void MainWindow::setupTabbar(QVBoxLayout *aLayout)
{
    QPixmap addTabMap;
    addTabMap.loadFromData(Resources::add_tab_png, sizeof(Resources::add_tab_png));
    m_addTabImage.addPixmap(addTabMap);
    QPushButton * button = new QPushButton(m_addTabImage, "");
    button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
    button->setStyleSheet("QPushButton {min-height:24px;min-width:24px;margin-top:2px;}");
    button->setFocusPolicy(Qt::NoFocus);
    QGridLayout * layout = new QGridLayout;

    m_tabBar = new QTabBar;
    m_tabBar->setStyleSheet("QTabBar::tab { min-height: 32px;}");
    //m_tabBar->setMaximumWidth(600);
    layout->addWidget(m_tabBar, 0, 0, Qt::AlignLeft);
    layout->addWidget(button, 0, 1, Qt::AlignLeft);
    layout->setSpacing(0);
    layout->setHorizontalSpacing(0);
    layout->setContentsMargins(0,0,0,0);
    layout->setColumnStretch(1, 10);
    aLayout->addLayout(layout);
    m_tabBar->setTabsClosable(true);
    m_tabBar->setExpanding(true);
    m_tabBar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
    connect(m_tabBar, SIGNAL(tabCloseRequested(int)), this, SLOT(onTabClose(int)));
    connect(m_tabBar, SIGNAL(currentChanged(int)), this, SLOT(onTabChanged(int)));
    connect(button, SIGNAL(clicked()), this, SLOT(onAddTabPressed()));
}


void MainWindow::openProjectTab()
{
    int count = m_tabBar->count();
    int newTabIndex = m_tabBar->insertTab(count, "Project");
    QVariant newTabData("project_tab");
    m_tabBar->setTabData(newTabIndex, newTabData);
    m_tabBar->setCurrentIndex(newTabIndex);
    if(count == 0)
        onTabChanged(0);

    updateWindowTitle();
    updateToolbar();
}

void MainWindow::openGrepTab()
{
    //may be it is opened already
    int count = m_tabBar->count();
    bool found = false;
    for(int i = 0; i < count; i++)
    {
        if(getTabType(i) == "grep_tab")
        {
            found = true;
            m_tabBar->setCurrentIndex(i);

        }
    }
    if(!found)
    {
        int newTabIndex = m_tabBar->insertTab(count - 1, "GREP");
        QVariant newTabData("grep_tab");
        m_tabBar->setTabData(newTabIndex, newTabData);
        m_tabBar->setCurrentIndex(newTabIndex);
    }
    updateDumpView(m_grepManager->getHtml());
    updateWindowTitle();
    updateToolbar();
}

void MainWindow::openSettingsTab()
{
    //may be it is opened already
    int count = m_tabBar->count();
    bool found = false;
    for(int i = 0; i < count; i++)
    {
        if(getTabType(i) == "settings_tab")
        {
            found = true;
            m_tabBar->setCurrentIndex(i);

        }
    }
    if(!found)
    {
        int newTabIndex = m_tabBar->insertTab(count - 1, m_settingsImage, "Settings");
        QVariant newTabData("settings_tab");
        m_tabBar->setTabData(newTabIndex, newTabData);
        m_tabBar->setCurrentIndex(newTabIndex);
    }
    //updateDumpView(m_grepManager->getHtml());
    updateWindowTitle();
    updateToolbar();
}


void MainWindow::openCodeTab(LuaFile * aFile)
{
    int count = m_tabBar->count();
    QString fileName = QFileInfo(aFile->getPath()).fileName();
    for(int i = 0; i < count; i++)
    {
        if(getTabType(i) == aFile->getPath())
        {
            m_tabBar->setCurrentIndex(i);
            updateToolbar();
            int scrollOffset = aFile->getScrollOffset();
            m_codeEditor->verticalScrollBar()->setValue(scrollOffset);
            return;
        }
    }


    int newTabIndex = m_tabBar->insertTab(count - 1, fileName);
    QVariant newTabData(aFile->getPath());
    m_tabBar->setTabData(newTabIndex, newTabData);
    m_tabBar->setCurrentIndex(newTabIndex);
    m_projectManager->setCurrentFile(aFile->getPath());
    LuaLexer * lexer = (LuaLexer *)m_codeEditor->lexer();
    lexer->setParser(aFile->getTokenParser());
    m_codeEditor->clearAnnotations();
    m_codeEditor->setText(aFile->getText());
    m_codeEditor->setFocus();

   updateWindowTitle();
}


void MainWindow::onTabChanged(int aTab)
{
    if(!m_processTabChanges)
        return;

    QVariant tabData = m_tabBar->tabData(aTab);
    QString data = tabData.toString();
    //if( data == "new_tab")
      //  openProjectTab();
    if(data == "project_tab")
    {
        //show project
        m_codeEditor->hide();
        m_functionsList->hide();
        m_searchPanel->hide();
        m_dumpView->hide();        
        m_projectView->show();
        m_projectFilter->show();
        m_projectFilter->setText("");
        m_projectManager->setFilter("");
        updateProjectView();
    }
    else if(data == "grep_tab")
    {
        //show grep tab
        m_codeEditor->hide();
        m_functionsList->hide();
        m_searchPanel->hide();
        m_projectView->hide();
        m_projectFilter->hide();        
        m_dumpView->show();
        updateDumpView(m_grepManager->getHtml());

    }
    else if(data == "settings_tab")
    {
        //show settings tab
        m_codeEditor->hide();
        m_functionsList->hide();
        m_searchPanel->hide();
        m_projectView->show();
        m_projectFilter->show();
        m_dumpView->hide();
        m_projectFilter->setText("");
        SettingsManager::Instance()->setFilter("");
        updateSettingsView();
    }
    else//code tab
    {
        //show code
        m_projectView->hide();
        m_projectFilter->hide();
        m_dumpView->hide();        
        m_codeEditor->show();
        m_functionsList->show();
        LuaFile * file = m_projectManager->getFileByPath(data);
        if(file)
        {            
            LuaLexer * lexer = (LuaLexer *)m_codeEditor->lexer();
            lexer->setParser(file->getTokenParser());
            int scrollOffset = file->getScrollOffset();
            m_codeEditor->clearAnnotations();
            m_codeEditor->setText(file->getText());            
            m_codeEditor->verticalScrollBar()->setValue(scrollOffset);
            //file->setScrollOffset(scrollOffset);
            m_projectManager->setCurrentFile(data);
            m_processFunctionsListChanges = false;
            //fill functions list
            m_functionsList->clear();
            QStringList globals;
            file->getAllGlobalFunctions(globals);
            globals.sort();
            m_functionsList->addItems(globals);
            QStringList locals;
            file->getAllLocalFunctions(locals);
            locals.sort();
            m_functionsList->addItems(locals);
            m_functionsList->insertItem(0, "");
            m_functionsList->setCurrentIndex(0);
            m_processFunctionsListChanges = true;
        }

    }
    updateToolbar();
    int count = m_tabBar->count();
    QStringList tabs;
    for(int i = 0; i < count - 1; i++)
    {
        tabs.append(getTabType(i));
    }
    SettingsManager::Instance()->setOpenedTabs(tabs);
    SettingsManager::Instance()->setCurrentTab(data);
    SettingsManager::Instance()->save();

}

void MainWindow::addFile()
{
    QFileInfo project(m_projectManager->getProjectFile());
    QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Add Lua Files To Project"),
                                                     project.dir().path(),
                                                     tr("Lua (*.lua)"));
    if(fileNames.size() == 0)
        return;
    for(int i = 0; i < fileNames.size(); i++)
        m_projectManager->addFile(fileNames[i]);
    updateProjectView();
    updateToolbar();
}

void MainWindow::importDirectory()
{
    QFileInfo project(m_projectManager->getProjectFile());
    QString dir = QFileDialog::getExistingDirectory(this, tr("Import Lua Files From Directory"),
                                                    project.dir().path(),
                                                    QFileDialog::ShowDirsOnly
                                                    | QFileDialog::DontResolveSymlinks);
    if(dir == "")
        return;
    m_projectManager->importFilesFromDirectory(dir);
    updateProjectView();
    updateToolbar();
}

void MainWindow::openProject(QString aProject)
{
    bool isCancelled = ensureProjectIsSaved();
    if(!isCancelled)
    {
        m_projectManager->load(aProject);
        SettingsManager::Instance()->addRecentProject(aProject);        
        SettingsManager::Instance()->save();
    }
    updateProjectView();
    updateToolbar();
    //close code tabs
    m_processTabChanges = false;
    int count  = m_tabBar->count();
    for(int i = count -1; i >= 0; i--)
        m_tabBar->removeTab(i);
    m_processTabChanges = true;
    openProjectTab();
}

void MainWindow::openProject()
{
    QFileInfo project(m_projectManager->getProjectFile());
    QString fileName = QFileDialog::getOpenFileName(this, tr("Open Project"),
                                                     project.dir().path(),
                                                     tr("Luacode Project (*.luacode)"));
    if(fileName == "")
        return;
    openProject(fileName);
}

void MainWindow::newProject()
{
    ensureProjectIsSaved();
    m_processTabChanges = false;
    //close all tabs but last
    int tabsCount = m_tabBar->count();
    for(int i = 0; i < tabsCount - 1; i++)
        m_tabBar->removeTab(i);
    m_processTabChanges = true;
    m_projectManager->resetProject();
    openProjectTab();
}

void MainWindow::onLinkClicked(const QUrl & url)
{
    QString urlString = url.toString();
    if(urlString.startsWith("open:"))
    {
        QString filePath = urlString.right(urlString.length() - 5);
        LuaFile * file = m_projectManager->getFileByPath(filePath);
        if(!file)
            return;
        openCodeTab(file);
        updateToolbar();
    }
    else if(urlString == "addfile")
        addFile();
    else if (urlString == "importdir")
        importDirectory();
    else if(urlString == "openproject")
        openProject();
    else if(urlString == "newproject")
        newProject();
    else if (urlString.startsWith("excludedir:"))
    {
        QString dirPath = urlString.right(urlString.length() - QString("excludedir:").length());
        m_projectManager->excludeDirectory(dirPath);
        updateProjectView();
        updateToolbar();
    }
    else if (urlString.startsWith("newfile:"))
    {
        QString dirPath = urlString.right(urlString.length() - QString("newfile:").length());
        QString fileName = QFileDialog::getSaveFileName(this,
                                                "New Lua File", dirPath, "*.lua");
        if(fileName == "")
            return;
        QFileInfo info(fileName);
        if(info.suffix() != ".lua")
            fileName+= ".lua";
        m_projectManager->addNewFile(fileName);
        updateProjectView();
        updateToolbar();
    }
    else if (urlString.startsWith("excludefile:"))
    {
        QString path = urlString.right(urlString.length() - QString("excludefile:").length());
        m_projectManager->excludeFile(path);
        updateProjectView();
        updateToolbar();
        closeFileTab(path);
    }
    else if (urlString.startsWith("openproject:"))
    {
        QString path = urlString.right(urlString.length() - QString("openproject:").length());
        openProject(path);
    }
    else if(urlString.startsWith("goto:"))
    {
        QString link = urlString.right(urlString.length() - QString("goto:").length());
        QList<QString> components = link.split(":");
        if(components.count() < 2)
            return;
        bool ok;
        int offset = components[1].toInt(&ok);
        if(!ok)
            return;
        int oldOffset = m_codeEditor->getCursorOffset();
        m_navigationManager->addItem(getCurrentTabType(), oldOffset);
        LuaFile * file = m_projectManager->getFileByPath(components[0]);
        if(!file)
            return;
        openCodeTab(file);
        m_codeEditor->goToOffset(offset);
        m_navigationManager->addItem(components[0], offset);
        updateToolbar();
    }
    else if(urlString.startsWith("set:"))
    {
        QString link = urlString.right(urlString.length() - QString("set:").length());
        SettingsManager::Instance()->getSetting(link).processLink();
        SettingsManager::Instance()->save();
        if(getCurrentTabType() == "settings_tab")
            updateSettingsView();
        m_codeEditor->initFromSettings();
    }
}


void MainWindow::onTextChanged()
{
    m_codeEditor->clearAnnotations();
    int tab = m_tabBar->currentIndex();
    QVariant tabData = m_tabBar->tabData(tab);
    QString data = tabData.toString();
    LuaFile * file = m_projectManager->getFileByPath(data);
    if(!file)
        return;    
    QString text = m_codeEditor->text();
    LuaLexer * lexer = (LuaLexer *)m_codeEditor->lexer();
    if(lexer)
        lexer->setCompleteOverdraw(true);
    if(text.length() > 0)
    {
        file->setContent(text);
    }

    if(lexer)
        lexer->setCompleteOverdraw(false);
    updateToolbar();
}

void MainWindow::open()
{

}

void MainWindow::save()
{

}

void MainWindow::quit()
{

}



MainWindow::~MainWindow()
{
    //delete ui;
    delete m_grepManager;
    delete m_navigationManager;
    delete m_gotoControl;
}



void MainWindow::onCompletionSelected(int aListId, const QString aItemText)
{
    if(aListId == 1)//code completion choice
    {
        int wordOffset = m_codeEditor->getWordOffset();
        int line = 0;
        int index = 0;
        m_codeEditor->getCursorPosition(&line, &index);
        m_codeEditor->setSelection(line, index - wordOffset - 1, line, index);
        m_codeEditor->replaceSelectedText(aItemText);
    }
    else if(aListId == 2)//global links choice
    {
        QString link = m_codeEditor->getGlobalLinkByFormattedLink(aItemText);
        if(link != "")
            onEditorLinkClicked(link);

    }
    //m_codeEditor->insert(aItemText);
}

void MainWindow::onToolbarAction(QAction *action)
{
    //TODO declare these string constants in one place
    if(action->iconText() == "Quit")
        close();
    else if(action->iconText() == "Save Project")
    {
        QString fileName;
        if(m_projectManager->isTemporaryProject())
        {
            fileName = QFileDialog::getSaveFileName(this,
                "Save Project File", m_projectManager->getProjectName());
            if(fileName == "")
                return;
            QFileInfo info(fileName);
            if(info.suffix() != "luacode")
                fileName+= ".luacode";
        }
        else
        {
            fileName = m_projectManager->getProjectFile();
        }
        m_projectManager->save(fileName);
        SettingsManager::Instance()->addRecentProject(fileName);
        SettingsManager::Instance()->save();
        updateWindowTitle();
    }
    else if (action->iconText() == "Open Project")
        openProject();
    else if (action->iconText() == "Add Files")
        addFile();
    else if (action->iconText() == "Import Directory")
        importDirectory();
    else if (action->iconText() == "Save File")
    {
        int tab = m_tabBar->currentIndex();
        QVariant tabData = m_tabBar->tabData(tab);
        QString data = tabData.toString();
        LuaFile * file = m_projectManager->getFileByPath(data);
        if(file)
        {
            file->save();
        }
    }
    else if (action->iconText() == "Save All")
    {
        m_projectManager->saveAllFiles();
    }
    else if (action->iconText() == "New Project")
        newProject();
    else if(action->iconText() == "Find")
    {
        onSearchRequested();
    }
    else if(action->iconText() == "Back")
    {
        QString newFile;
        int offset;
        bool result = m_navigationManager->previous(newFile, offset);
        if(result)
        {
            //switch to newFile or open it
            LuaFile * file = m_projectManager->getFileByPath(newFile);
            if(file)
            {
                openCodeTab(file);
                m_codeEditor->goToOffset(offset);
            }
        }
    }
    else if(action->iconText() == "Forward")
    {
        QString newFile;
        int offset;
        bool result = m_navigationManager->next(newFile, offset);
        if(result)
        {
            //switch to newFile or open it
            LuaFile * file = m_projectManager->getFileByPath(newFile);
            if(file)
            {
                openCodeTab(file);
                m_codeEditor->goToOffset(offset);
            }
        }
    }
    else if(action->iconText() == "Check")
    {
        checkFile(getCurrentTabType());
    }
    else if(action->iconText() == "GREP")
    {
        bool isVisible = m_grepPanel->isVisible();
        showGrepPanel(!isVisible);
    }
    else if(action->iconText() == "Settings")
    {
        openSettingsTab();
    }
    updateToolbar();
}

void MainWindow::onTabClose(int aIndex)
{
    if(aIndex == m_tabBar->count() - 1 && m_tabBar->count() > 2)
        m_tabBar->setCurrentIndex(m_tabBar->count() - 2);
    m_tabBar->removeTab(aIndex);
    if(m_tabBar->count() == 0)
        openProjectTab();
}

void MainWindow::onEditorLinkClicked(QString aLink)
{
    if(aLink.startsWith("local:"))
    {
        int oldOffset = m_codeEditor->getCursorOffset();
        m_navigationManager->addItem(getCurrentTabType(), oldOffset);
        QString strOffset = aLink.right(aLink.length() - 6);//6 is a length of local:
        bool ok;
        int offset = strOffset.toInt(&ok);
        if(ok)
        {
            m_codeEditor->goToOffset(offset);
            m_navigationManager->addItem(getCurrentTabType(), offset);
            updateToolbar();
        }

    }
    else if(aLink.startsWith("global:"))
    {
        int oldOffset = m_codeEditor->getCursorOffset();
        m_navigationManager->addItem(getCurrentTabType(), oldOffset);
        QStringList components;
        m_codeEditor->parseGlobalLink(aLink, components);
        bool ok = false;
        QString strOffset = components[0];
        int offset = strOffset.toInt(&ok);
        if(!ok)
            return;
        //open file or switch to it
        int tabsCount = m_tabBar->count();
        for(int i = 0; i < tabsCount; i++)
        {
            if(getTabType(i) == components[1])
            {
                m_tabBar->setCurrentIndex(i);
                m_codeEditor->goToOffset(offset);
                m_navigationManager->addItem(components[1], offset);
                updateToolbar();
                return;
            }
        }
        //couldn't switch, opening new tab
        LuaFile * file = m_projectManager->getFileByPath(components[1]);
        if(!file)
            return;
        openCodeTab(file);
        m_codeEditor->goToOffset(offset);
        m_navigationManager->addItem(components[1], offset);
        updateToolbar();
    }
}


bool MainWindow::ensureProjectIsSaved()
{
    if(!m_projectManager->isSaved() && m_projectManager->hasFiles())
    {
        QMessageBox messageBox;
        messageBox.setText("Project " + m_projectManager->getProjectName() + " has been modified");
        //messageBox.addButton(QMessageBox::Discard);
        messageBox.setInformativeText("Do you want to save your changes?");
        messageBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
        messageBox.setDefaultButton(QMessageBox::Save);
        int result = messageBox.exec();
        if(result == QMessageBox::Save)
        {
            QString fileName = QFileDialog::getSaveFileName(this,
                "Save Project File", m_projectManager->getProjectName());
            if(fileName == "")
                return true;//take as Cancel
            QFileInfo info(fileName);
            if(info.suffix() != "luacode")
                fileName+= ".luacode";
            m_projectManager->save(fileName);
            SettingsManager::Instance()->addRecentProject(fileName);
            SettingsManager::Instance()->save();
            return false;
        }
        else if(result == QMessageBox::Discard)
        {
            return false;
        }
        else
        {
            //Cancel
            return true;
        }


    }
    return false;
}

void MainWindow::closeEvent(QCloseEvent *e)
{
    bool isCancelled = ensureProjectIsSaved();
    if(isCancelled)
        e->ignore();
    else
    {
        SettingsManager::Instance()->save();
        e->accept();
    }

}


void MainWindow::updateToolbar()
{
    //detect what tab are we in
    QString tabType = getCurrentTabType();
    m_toolbar->clear();
    if(tabType == "project_tab")
    {
        if(!m_projectManager->isSaved())
            m_toolbar->addAction(m_saveImage, "Save Project");
        m_toolbar->addAction(m_openProjectImage, "Open Project");
        m_toolbar->addAction(m_addFilesImage, "Add Files");
        m_toolbar->addAction(m_importDirectoryImage, "Import Directory");
        if(!m_projectManager->isTemporaryProject())
            m_toolbar->addAction(m_newProjectImage, "New Project");
    }
    else if(tabType == "grep_tab" || tabType == "settings_tab")
    {

    }
    else//code tab
    {
        LuaFile * file = m_projectManager->getFileByPath(tabType);
        if(file)
        {
            QAction * action = m_toolbar->addAction(m_backImage, "Back");
            if(m_navigationManager->canGoPrevious())
                action->setEnabled(true);
            else
                action->setEnabled(false);
            action = m_toolbar->addAction(m_forwardImage, "Forward");
            if(m_navigationManager->canGoNext())
                action->setEnabled(true);
            else
                action->setEnabled(false);
            if(!file->isSaved())
                m_toolbar->addAction(m_saveImage, "Save File");
            if(m_projectManager->hasUnsavedFiles())
                m_toolbar->addAction(m_saveAllImage, "Save All");
            m_toolbar->addAction(m_findImage, "Find");
            m_toolbar->addAction(m_checkImage, "Check");
        }
    }
    m_toolbar->addAction(m_grepImage, "GREP");
    if(tabType != "settings_tab")
        m_toolbar->addAction(m_settingsImage, "Settings");
    m_toolbar->addSeparator();
    m_toolbar->addAction(m_quitImage, "Quit");
}


/*void MainWindow::onFindTextChanged(QString aNewText)
{
    if(aNewText.length() == 0)
        return;//don't care about empty text field
    //check if we are in code tab
    QString tabType = getCurrentTabType();
    if(tabType != "project_tab" && tabType != "new_tab")
    {
        //code tab
        m_codeEditor->findAndScrollToWord(aNewText);
    }
}*/

QString MainWindow::getCurrentTabType()
{
   int tab = m_tabBar->currentIndex();
   return getTabType(tab);
}

QString MainWindow::getTabType(int aIndex)
{
    QVariant tabData = m_tabBar->tabData(aIndex);
    QString data = tabData.toString();
    return data;
}

void MainWindow::updateWindowTitle()
{
    QString tabType = getCurrentTabType();
    if(tabType == "project_tab")
    {
        QString mark;
        if(!m_projectManager->isSaved())
            mark = "*";
        setWindowTitle("Luacode - " + m_projectManager->getProjectName() + mark);
    }
    else if(tabType == "grep_tab")
    {
        setWindowTitle("Luacode - " + m_projectManager->getProjectName() + " GREP results");
    }
    else if(tabType == "settings_tab")
    {
        setWindowTitle("Luacode - " + m_projectManager->getProjectName() + " Settings");
    }
    else
    {
        //code tab
        QFileInfo info(tabType);
        LuaFile * file = m_projectManager->getFileByPath(tabType);
        QString mark;
        if(file && file->isSaved() == false)
            mark = "*";
        setWindowTitle("Luacode - " + info.fileName() + mark);
    }
}


void MainWindow::onCodeEditorScrolled(int aOffset)
{    
    QString currentType = getCurrentTabType();
    if(isCodeTabSelected())
    {
        //this is a code tab and we should remember corresponding scroll offset
        LuaFile * file = m_projectManager->getFileByPath(currentType);
        if(file)
            file->setScrollOffset(m_codeEditor->verticalScrollBar()->value());
    }
}

void MainWindow::onProjectFilterChanged(QString aText)
{
    if(getCurrentTabType() == "project_tab")
    {
        m_projectManager->setFilter(aText);
        updateProjectView();
    }
    else//settings
    {
        SettingsManager::Instance()->setFilter(aText);
        updateSettingsView();
    }


}

void MainWindow::onSearchRequested()
{
    m_searchPanel->show();
    m_searchPanel->setFindFocus();
    m_grepPanel->hide();
}

void MainWindow::onSearchPanelHide()
{
    m_codeEditor->setFocus();
}

void MainWindow::onFunctionChosen(QString aItem)
{
    if(aItem.length() == 0)
        return;
    int tab = m_tabBar->currentIndex();
    QVariant tabData = m_tabBar->tabData(tab);
    QString data = tabData.toString();
    LuaFile * file = m_projectManager->getFileByPath(data);
    if(file)
    {
        if(m_processFunctionsListChanges)
        {
            int oldOffset = m_codeEditor->getCursorOffset();
            m_navigationManager->addItem(data, oldOffset);

            int offset = file->getOffsetByFunctionHeader(aItem);
            m_codeEditor->goToOffset(offset);
            m_codeEditor->setFocus();
            //if(m_processFunctionsListChanges)

            m_navigationManager->addItem(data, offset);
            updateToolbar();
        }

    }
}

void MainWindow::onGrepDonePressed()
{
    showGrepPanel(false);
}

void MainWindow::onGrepPressed(QString aPattern)
{
    QStringList allFiles;
    m_projectManager->getAllFiles(allFiles);
    m_grepManager->doSearch(aPattern, allFiles);
    openGrepTab();
}

void MainWindow::onGoToChosen(QString aLink)
{
    onEditorLinkClicked(aLink);
}

void MainWindow::onWebViewScrolled(int dx, int dy, const QRect &rectToScroll)
{
    int scrollOffset = m_projectView->page()->mainFrame()->scrollBarValue(Qt::Vertical);
    QString tabType = getCurrentTabType();
    if(tabType == "project_tab")
        m_projectScrollPosition = scrollOffset;
    else if(tabType == "settings_tab")
        m_settingsScrollPosition = scrollOffset;
}

void MainWindow::onAddTabPressed()
{
    openProjectTab();
}

void MainWindow::updateProjectView()
{    
    m_projectView->setHtml(m_projectManager->getHtml());
    m_projectView->page()->mainFrame()->setScrollBarValue(Qt::Vertical,m_projectScrollPosition);
}

void MainWindow::updateSettingsView()
{
    m_projectView->setHtml(SettingsManager::Instance()->getHtml());
    m_projectView->page()->mainFrame()->setScrollBarValue(Qt::Vertical,m_settingsScrollPosition);
}


void MainWindow::updateDumpView(QString aContent)
{    
    int scrollOffset = m_dumpView->verticalScrollBar()->value();
    m_dumpView->setHtml(aContent);
    m_dumpView->verticalScrollBar()->setValue(scrollOffset);
}


void MainWindow::closeFileTab(QString aFile)
{
    int found = true;
    while(found)
    {
        found = false;
        int count = m_tabBar->count();
        for(int i = 0; i < count; i++)
        {
            QVariant tabData = m_tabBar->tabData(i);
            QString data = tabData.toString();
            if(data == aFile)
            {
                m_tabBar->removeTab(i);
                found = true;
                break;
            }
        }
    }
}


void MainWindow::checkFile(QString aFile)
{
    QProcess luac;
    luac.setProcessChannelMode(QProcess::MergedChannels);
    luac.start("luac -p "+aFile);
    luac.waitForFinished(-1);
    QByteArray output = luac.readAllStandardOutput();
    QString temp(output);
    QStringList lines = temp.split("\n");
    QString buffer;
    for(int i = 0; i < lines.count(); i++)
    {
        buffer = lines[i];
        //skip filename
        int index = buffer.indexOf(aFile);
        buffer = buffer.right(buffer.length() - index - aFile.length() - 1);
        //get line number
        index = buffer.indexOf(":");
        QString lineNumber = buffer.left(index);
        buffer = buffer.right(buffer.length() - index - 1);
        //the message is in buffer now
        bool ok = false;
        int iLineNumber = lineNumber.toInt(&ok);
        if(!ok)
            continue;
        //qDebug(buffer.toLocal8Bit().constData());
        m_codeEditor->annotate(iLineNumber - 1, buffer, EStyleErrorAnnotation);
    }
}

void MainWindow::showGrepPanel(bool aShow)
{
    if(aShow)
    {
        m_searchPanel->hide();
        m_grepPanel->show();
        m_grepPanel->setEditFocus();
    }
    else
    {
        m_grepPanel->hide();
        if(isCodeTabSelected())
        {
            m_codeEditor->setFocus();
        }
    }
}


void MainWindow::keyPressEvent(QKeyEvent *e)
{
    int key = e->key();
    //TODO keybindings in settings
    if(e->modifiers().testFlag(Qt::ControlModifier) == true
            && e->modifiers().testFlag(Qt::ShiftModifier) == true && key == 'F')
    {
        if(!m_grepPanel->isVisible())
            showGrepPanel(true);
        else
            showGrepPanel(false);
        e->accept();
        return;
    }


    if(e->modifiers().testFlag(Qt::ControlModifier) == true && key == 'O')
    {
        showGoToControl();
        e->accept();
        return;
    }
    if(m_grepPanel->isVisible() && key == Qt::Key_Escape)
    {
        showGrepPanel(false);
        e->accept();
        return;
    }

    QMainWindow::keyPressEvent(e);
}


void MainWindow::reopenTabs()
{
    QStringList tabs;
    SettingsManager::Instance()->getTabs(tabs);
    m_processTabChanges = false;
    int count  = m_tabBar->count();
    for(int i = count -1; i >= 0; i--)
        m_tabBar->removeTab(i);
    for(int i = 0; i < tabs.count(); i++)
    {
        QString tabType = tabs[i];
        if(tabType == "project_tab")
            openProjectTab();
        if(tabType == "settings_tab")
            openSettingsTab();
        else if(tabType != "grep_tab" && tabType != "settings_tab")
        {
            LuaFile * file = m_projectManager->getFileByPath(tabType);
            if(file)
                openCodeTab(file);
        }
    }
    m_processTabChanges  = true;
    QString currentTab = SettingsManager::Instance()->getCurrentTab();
    count  = m_tabBar->count();
    for(int i = 0; i < count; i++)
    {
        if(getTabType(i) == currentTab)
        {
            m_tabBar->setCurrentIndex(i);
            onTabChanged(i);
            m_searchPanel->hide();
            return;
        }
    }
    //not found, choose any tab
    openProjectTab();
}


void MainWindow::showGoToControl()
{
    //put it in the center
    int centerX = width()/2;
    int centerY = height()/2;

    int gotoWidth = width()*0.6;
    int gotoHeight = height()/8;

    m_gotoControl->setFixedSize(gotoWidth, gotoHeight);
    m_gotoControl->move(centerX - gotoWidth/2, centerY - gotoHeight/2);
    m_gotoControl->setAvalaibleHeight(height() - (centerY - gotoHeight/2));
    m_gotoControl->exec();
}


void MainWindow::hideGoToControl()
{
    m_gotoControl->hide();
}


bool MainWindow::isCodeTabSelected()
{
    QString currentType = getCurrentTabType();
    return  currentType != "project_tab"
            && currentType != "grep_tab" && currentType != "settings_tab" &&
            currentType != "guide_tab";
}


void MainWindow::setupStyleSheet()
{
    QString stylesheet;
    stylesheet += "QLineEdit { border-radius: 4px;}\n";
    //stylesheet += "QTabBar::tab:last { background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #E1E1E1, stop: 0.4 #DDDDDD, stop: 0.5 #D8D8D8, stop: 1.0 #D3D3D3);}\n";
    qApp->setStyleSheet(stylesheet);
}
